package cn.net.msg.service.base;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Transactional;

import cn.net.msg.model.TbFavourite;


@SuppressWarnings("unchecked")
@Transactional
public class DaoSupport implements DAO{

    @Resource(name="hibernateTemplate")
    private HibernateTemplate hibernateTemplate;

    @Override
    public void save(Object entity) {
        // TODO Auto-generated method stub
        hibernateTemplate.save(entity);
    }

    @Override
    public void delete(Object entity) {
        // TODO Auto-generated method stub
        hibernateTemplate.delete(entity);
    }

    @Override
    public void update(Object entity) {
        // TODO Auto-generated method stub
        hibernateTemplate.update(entity);
    }

    @Override
    public <T> T query(Class<T> entityClass, long id) {
        // TODO Auto-generated method stub
        return hibernateTemplate.get(entityClass, id);
    }

    @Override
    public <T> T query(Class<T> entityClass, int id) {
        // TODO Auto-generated method stub
        return hibernateTemplate.get(entityClass, id);
    }

    @Override
    public <T> List<T> queryAll(Class<?> className) {
        // TODO Auto-generated method stub
        return hibernateTemplate.find("from " + className.getName());
    }

    @Override
    public <T> List<T> paging(final Class<?> entityClass,final int index,final int size,final List<HashMap<String,Object>> queryParams,
            final Order order,final String... propertyName) {
        // TODO Auto-generated method stub
        List<T> list = hibernateTemplate.executeFind(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(entityClass);  
                setCriteriaParams(criteria,queryParams);                
                if (propertyName != null && propertyName.length > 0) {
                    switch (order) {
                    case ASC:
                        criteria.addOrder(org.hibernate.criterion.Order
                                .asc(propertyName[0]));
                        break;
                    case DESC:
                        criteria.addOrder(org.hibernate.criterion.Order
                                .desc(propertyName[0]));
                        break;
                    }
                }
                criteria.setFirstResult(index);
                criteria.setMaxResults(size);  
                return criteria.list();
            }
        }); 
        return list;
    }

    @Override
    public long getSumRecord(Class<?> className) {
        // TODO Auto-generated method stub
        List<Long> count = new ArrayList<Long>();
        count = hibernateTemplate.find("select COUNT(*) from "
                + className.getName());
        return count.size() > 0 ? (count.get(0)) : 0L;
    }

    @Override
    public long sumPage(Class<?> className, int size) {
        // TODO Auto-generated method stub
        List<Long> count = new ArrayList<Long>();
        count = hibernateTemplate.find("select COUNT(*) from "
                + className.getName());
        return count.size() > 0 ? (count.get(0) - 1 + size) / size : 0L;
    }

    @Override
    public <T> List<T> queryByProperty(final Class<?> className,
            final Map<String, Object> params) {
        // TODO Auto-generated method stub
        return hibernateTemplate.executeFind(new HibernateCallback() {
            @Override
            public List<?> doInHibernate(Session session)
            throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(className);
                for (String field : params.keySet())
                    criteria.add(Property.forName(field).eq(params.get(field)));
                return criteria.list();
            }
        });
    }

    @Override
    public long queryByPropertyGetSumPage(final Class<?> className,
            final Map<String, Object> params,final int size) {
        // TODO Auto-generated method stub
        List<Integer> object = hibernateTemplate
        .executeFind(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(className);
                for (String field : params.keySet())
                    criteria.add(Property.forName(field).eq(
                            params.get(field)));
                criteria.setProjection(Projections.rowCount());
                return criteria.list();
            }
        });
        int count = object == null ? 0 : object.get(0);
        return count > 0 ? (count + size - 1) / size : 0L;
    }

    @Override
    public long queryByPropertyGetSumRecord(final Class<?> className,
            final Map<String, Object> params) {
        // TODO Auto-generated method stub
        List<Integer> object = hibernateTemplate
        .executeFind(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(className);
                for (String field : params.keySet())
                    criteria.add(Property.forName(field).eq(
                            params.get(field)));
                criteria.setProjection(Projections.rowCount());
                return criteria.list();
            }
        });
        return object == null ? 0 : object.get(0);
    }

    @Override
    public <T> List<T> queryByPropertyPaging(final Class<?> className,
            final Map<String, Object> params,final  int index,final  int size,final  Order order,
            final String... field) {
        // TODO Auto-generated method stub
        return hibernateTemplate.executeFind(new HibernateCallback() {
            @Override
            public List<?> doInHibernate(Session session)
            throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(className);
                for (String f : params.keySet())
                    criteria.add(Property.forName(f).eq(params.get(f)));
                if (field != null && field.length != 0) {
                    switch (order) {
                    case ASC:
                        criteria.addOrder(org.hibernate.criterion.Order
                                .asc(field[0]));
                        break;
                    case DESC:
                        criteria.addOrder(org.hibernate.criterion.Order
                                .desc(field[0]));
                        break;
                    }
                }
                criteria.setFirstResult(index);
                criteria.setMaxResults(size);
                return criteria.list();
            }
        });
    }

    @Override
    public void saveOrUpdate(Object entity) {
        // TODO Auto-generated method stub
        hibernateTemplate.saveOrUpdate(entity);
    }

    @Override
    public int bulkUpdate(String queryString) {
        // TODO Auto-generated method stub
        return hibernateTemplate.bulkUpdate(queryString);
    }

    @Override
    public int bulkUpdate(String queryString, Object... values) {
        // TODO Auto-generated method stub
        return hibernateTemplate.bulkUpdate(queryString, values);
    }

    @Override
    public void deleteAll(Collection<?> collection) {
        // TODO Auto-generated method stub
        hibernateTemplate.deleteAll(collection);
    }

    @Override
    public <T> List<T> Querylike(final Class<?> className,final String field,
            final String value,final MatchMode matchMode) {
        // TODO Auto-generated method stub
        List objects = new ArrayList<Object>();
        objects = hibernateTemplate.executeFind(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                Criteria criteria = session.createCriteria(className);
                criteria.add(Property.forName(field).like(value, matchMode));
                return criteria.list();
            }
        });
        return objects;
    }

    @Override
    public <T> Object executeQuery(final String hql,final int maxSize, final List<Object> values, final int firstResult,final int maxResult) {
        // TODO Auto-generated method stub
        return hibernateTemplate.execute(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                setParams(query, values);
                if (maxSize != 0) {
                    query.setMaxResults(maxSize);
                }
                if (maxResult != 0) {
                    query.setFirstResult(firstResult);
                    query.setMaxResults(maxResult);
                }
                return query.list();
            }
        });
    }

    @Override
    public <T> Object executeSacale(final String hql,final List<Object> values) {
        // TODO Auto-generated method stub
        return hibernateTemplate.execute(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                setParams(query, values);
                query.setMaxResults(1);
                return query.uniqueResult();
            }
        });
    }

    @Override
    public int executNonQuery(final String hql,final List<Object> values) {
        // TODO Auto-generated method stub
        return hibernateTemplate.execute(new HibernateCallback() {
            @Override
            public Integer doInHibernate(Session session)
            throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                setParams(query, values);
                return query.executeUpdate();
            }
        });
    }

    @Override
    public void truncate(final String tableName) {
        // TODO Auto-generated method stub
        hibernateTemplate.execute(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                session.createSQLQuery("truncate table " + tableName).executeUpdate();
                return new ArrayList();
            }
        });
    }

    private void setParams(Query query, List<Object> values) {
        if (!isEmptyOrNull(values)) {
            for (int i = 0; i < values.size(); i++) {
                query.setParameter(i, values.get(i));
            }
        }
    }

    /**
     * criteria方式的填充查询条件
     * @param criteria
     * @param queryParams
     * 详见：http://blog.csdn.net/woshixuye/article/details/7200590
     */
    private void setCriteriaParams(Criteria criteria, List<HashMap<String,Object>> queryParams){
        if(queryParams != null && queryParams.size() > 0){
            for(Map<String,Object> map : queryParams){
                if (map.get("opera").equals("eq")) { // =
                    criteria.add(Restrictions.eq(map.get("field").toString(), map.get("value")));
                }
                if (map.get("opera").equals("ne")) { // <>
                    criteria.add(Restrictions.ne(map.get("field").toString(), map.get("value")));
                }
                if (map.get("opera").equals("gt")) { // >
                    criteria.add(Restrictions.gt(map.get("field").toString(), map.get("value")));
                }
                if (map.get("opera").equals("ge")) { // >=
                    criteria.add(Restrictions.ge(map.get("field").toString(), map.get("value")));
                }
                if (map.get("opera").equals("lt")) { // <
                    criteria.add(Restrictions.lt(map.get("field").toString(), map.get("value")));
                }
                if (map.get("opera").equals("le")) { // <=
                    criteria.add(Restrictions.le(map.get("field").toString(), map.get("value")));
                }
                if (map.get("opera").equals("like")) { // 字符串模式匹配
                    criteria.add(Restrictions.like(map.get("field").toString(), "%" + map.get("value") + "%"));
                }               
            }
        }
    }


    /**
     * 判断值是否为空或
     *
     * @param values
     * @return
     */
    private boolean isEmptyOrNull(Object... values) {
        if (values == null || values.length == 0)
            return true;
        return false;
    }

    @Override
    public <T> Object executeSumscoreNativeQuery(final String sql,final long userid) {
        // TODO Auto-generated method stub
        return hibernateTemplate.execute(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                SQLQuery query = session.createSQLQuery(sql);
                query.addScalar("sumscore", Hibernate.STRING);   //返回值类型  
                query.setLong(0, userid); //输入参数 
                query.setMaxResults(1);
                return query.uniqueResult();
            }
        });
    }

    @Override
    public <T> Object executeGobalRankNativeQuery(final String sql,
            final long userid) {
        // TODO Auto-generated method stub
        return hibernateTemplate.execute(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                SQLQuery query = session.createSQLQuery(sql);
                query.addScalar("gobalrank", Hibernate.INTEGER);   //返回值类型  
                query.setLong(0, userid); //输入参数 
                query.setMaxResults(1);
                return query.uniqueResult();
            }
        });
    }

    @Override
    public <T> Object executeExamRankNativeQuery(final String sql,final long userid, final String examFileid) {
        // TODO Auto-generated method stub
        return hibernateTemplate.execute(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                SQLQuery query = session.createSQLQuery(sql);
                query.addScalar("examRank", Hibernate.INTEGER);   //返回值类型  
                query.setString(0, examFileid); //输入参数 
                query.setLong(1, userid);
                query.setString(2, examFileid);
                query.setMaxResults(1);
                return query.uniqueResult();
            }
        });
    }

    @Override
    public <T> Object executeGetPopFavouriteListNativeQuery(final String sql,
            final int index, final int size) {
        // TODO Auto-generated method stub
        return hibernateTemplate.execute(new HibernateCallback() {
            @Override
            public Object doInHibernate(Session session)
            throws HibernateException, SQLException {
                SQLQuery query = session.createSQLQuery(sql);  
                query.addEntity(TbFavourite.class);
                query.setFirstResult(index);
                query.setMaxResults(size);
                return query.list();
            }
        });
    }
}
